package com.ccteam.fluidmusic.view.adapters.paging

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.paging.LoadState
import androidx.paging.LoadStateAdapter
import androidx.paging.PagingDataAdapter
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.ccteam.fluidmusic.databinding.GlobalPagingLoadStateItemBinding
import com.orhanobut.logger.Logger

/**
 * @author Xiaoc
 * @since 2021/2/16
 *
 * 基于 [PagingDataAdapter] 分页库的基本RecyclerView适配器
 * 其下有两个子类：[MultiTypePagingAdapter] [PagingAdapter]
 *
 * 它主要封装了一下基本数据的传递，并且基于分页
 */
abstract class BasePagingAdapter<E: Any,VH: RecyclerView.ViewHolder>(
    diffItemCallback: DiffUtil.ItemCallback<E>
): PagingDataAdapter<E, VH>(diffItemCallback) {

    /**
     * 创建视图容器
     * 会调用 [createPagingViewHolder] 抽象方法调用用户自己实现的视图容器
     *
     * 一旦出现viewHolder为空的情况，目前的处理是直接抛出异常
     */
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH {
        return createPagingViewHolder(parent,viewType) ?: throw IllegalArgumentException("无效不支持的布局：$viewType")
    }

    /**
     * 绑定视图与数据
     */
    override fun onBindViewHolder(holder: VH, position: Int) {
        onBindViewHolder(holder,position, mutableListOf())
    }

    /**
     * 绑定视图与数据
     * 会调用 [bindPagingItem] 让子类去填充对应布局的内容
     */
    override fun onBindViewHolder(holder: VH, position: Int, payloads: MutableList<Any>) {
        bindPagingItem(holder,position,getItem(position),payloads)
    }

    /**
     * 创建视图ViewBinding视图容器，为抽象方法，需要自己实现
     */
    abstract fun createPagingViewHolder(parent: ViewGroup, viewType: Int): VH?

    /**
     * 绑定视图与数据
     */
    abstract fun bindPagingItem(holder: VH,
                                position: Int,
                                item: E?,
                                payloads: MutableList<Any>)
}

/**
 * 自定义的分页加载状态适配器
 * 他继承 [LoadStateAdapter]
 * 它的父类会传递来一个 [LoadState]
 * 该对象会包含当前加载的状态，根据其状态进行对应内容的显隐
 *
 * @param dataAdapter 分页数据列表适配器
 * @param shouldShowEndReached 是否展示到底页面
 * @param retry 重试操作
 */
class CustomLoadStateAdapter(
    private val dataAdapter: PagingAdapter<*,*,*>,
    private val shouldShowEndReached: Boolean = false,
    private val retry: () -> Unit): LoadStateAdapter<LoadStateViewHolder>() {

    /**
     * 创建视图容器
     * 返回的是我们自定义的 [LoadStateViewHolder] 视图容器
     * 该容器定义了根据什么状态显示什么内容
     */
    override fun onCreateViewHolder(
        parent: ViewGroup,
        loadState: LoadState
    ): LoadStateViewHolder =
        LoadStateViewHolder(retry,
            GlobalPagingLoadStateItemBinding.inflate(
                LayoutInflater.from(parent.context),parent,false))

    /**
     * 绑定视图数据
     */
    override fun onBindViewHolder(
        holder: LoadStateViewHolder,
        loadState: LoadState
    ) = holder.bindState(loadState)

    override fun displayLoadStateAsItem(loadState: LoadState): Boolean {
        return super.displayLoadStateAsItem(loadState)
                || (loadState is LoadState.NotLoading &&
                loadState.endOfPaginationReached && shouldShowEndReached && dataAdapter.itemCount > 0)
    }
}